package cn.com.anypay.manager.payment.service;

import cn.com.anypay.manager.payment.core.IPaymentChannel;
import cn.com.anypay.manager.payment.core.PaymentException;
import cn.com.anypay.manager.payment.dto.*;
import cn.com.anypay.manager.payment.manager.PaymentChannelManager;
import cn.com.anypay.manager.payment.manager.PaymentManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 统一通知服务 - 现在只依赖PaymentManager
 *
 * 提供支付通知的统一处理接口，包括回调验证、结果处理等
 *
 * @author AnyPay Team
 * @version 1.0
 * @since 2025-07-05
 */
@Service
public class NotifyService {

    private static final Logger logger = LoggerFactory.getLogger(NotifyService.class);

    @Autowired
    private PaymentManager paymentManager;

    /**
     * 处理支付通知
     *
     * @param channelId 渠道ID
     * @param notifyData 通知数据
     * @return 处理结果
     * @throws PaymentException 处理失败时抛出
     */
    public PaymentResultDTO processPaymentNotify(String channelId, String notifyData) throws PaymentException {
        if (channelId == null || channelId.trim().isEmpty()) {
            throw new PaymentException("INVALID_REQUEST", "Channel ID is null or empty");
        }

        if (notifyData == null || notifyData.trim().isEmpty()) {
            throw new PaymentException("INVALID_REQUEST", "Notify data is null or empty");
        }

        logger.info("开始处理支付通知，渠道: {}", channelId);

        try {
            // 获取可用渠道
            IPaymentChannel channel = paymentManager.getAvailableChannel(channelId);

            // 验证通知数据
            if (!channel.verifyCallback(notifyData)) {
                logger.error("通知验证失败，渠道: {}", channelId);
                throw new PaymentException("NOTIFY_VERIFY_FAILED", "Notify verification failed", channelId);
            }

            // 处理通知数据
            PaymentResultDTO result = channel.processCallback(notifyData);

            logger.info("支付通知处理成功，渠道: {}, 订单状态: {}", channelId, result.getStatus());
            return result;

        } catch (PaymentException e) {
            logger.error("支付通知处理失败，渠道: {}, 错误: {}", channelId, e.getMessage());
            throw e;
        } catch (Exception e) {
            logger.error("支付通知处理异常，渠道: {}", channelId, e);
            throw new PaymentException("NOTIFY_PROCESS_ERROR", "Failed to process notify", e, channelId);
        }
    }

    /**
     * 验证通知签名
     *
     * @param channelId 渠道ID
     * @param notifyData 通知数据
     * @return 验证结果
     * @throws PaymentException 验证失败时抛出
     */
    public boolean verifyNotifySignature(String channelId, String notifyData) throws PaymentException {
        if (channelId == null || channelId.trim().isEmpty()) {
            throw new PaymentException("INVALID_REQUEST", "Channel ID is null or empty");
        }

        if (notifyData == null || notifyData.trim().isEmpty()) {
            throw new PaymentException("INVALID_REQUEST", "Notify data is null or empty");
        }

        logger.info("开始验证通知签名，渠道: {}", channelId);

        try {
            // 获取可用渠道
            IPaymentChannel channel = paymentManager.getAvailableChannel(channelId);

            // 验证签名
            boolean verified = channel.verifyCallback(notifyData);

            logger.info("通知签名验证{}，渠道: {}", verified ? "成功" : "失败", channelId);
            return verified;

        } catch (PaymentException e) {
            logger.error("通知签名验证失败，渠道: {}, 错误: {}", channelId, e.getMessage());
            throw e;
        } catch (Exception e) {
            logger.error("通知签名验证异常，渠道: {}", channelId, e);
            throw new PaymentException("NOTIFY_VERIFY_ERROR", "Failed to verify notify signature", e, channelId);
        }
    }

    /**
     * 批量处理通知
     *
     * @param notifications 通知列表
     * @return 处理结果映射
     */
    public Map<String, PaymentResultDTO> processBatchNotify(Map<String, String> notifications) {
        Map<String, PaymentResultDTO> results = new HashMap<>();

        if (notifications == null || notifications.isEmpty()) {
            logger.warn("批量通知处理请求为空");
            return results;
        }

        logger.info("开始批量处理通知，数量: {}", notifications.size());

        for (Map.Entry<String, String> entry : notifications.entrySet()) {
            String channelId = entry.getKey();
            String notifyData = entry.getValue();

            try {
                PaymentResultDTO result = processPaymentNotify(channelId, notifyData);
                results.put(channelId, result);
            } catch (PaymentException e) {
                logger.error("批量通知处理失败，渠道: {}, 错误: {}", channelId, e.getMessage());
                PaymentResultDTO errorResult = PaymentResultDTO.failure(e.getErrorCode(), e.getMessage());
                results.put(channelId, errorResult);
            }
        }

        logger.info("批量通知处理完成，成功: {}, 失败: {}",
            results.values().stream().mapToInt(r -> r.isSuccess() ? 1 : 0).sum(),
            results.values().stream().mapToInt(r -> r.isSuccess() ? 0 : 1).sum());

        return results;
    }

    /**
     * 生成通知响应
     *
     * @param channelId 渠道ID
     * @param success 处理是否成功
     * @return 响应内容
     */
    public String generateNotifyResponse(String channelId, boolean success) {
        logger.info("生成通知响应，渠道: {}, 成功: {}", channelId, success);

        try {
            // 获取可用渠道
            IPaymentChannel channel = paymentManager.getAvailableChannel(channelId);

            // 根据渠道类型生成不同的响应
            if (success) {
                return generateSuccessResponse(channelId);
            } else {
                return generateFailureResponse(channelId);
            }

        } catch (Exception e) {
            logger.error("生成通知响应异常，渠道: {}", channelId, e);
            return generateFailureResponse(channelId);
        }
    }

    /**
     * 重新处理通知
     *
     * @param channelId 渠道ID
     * @param notifyData 通知数据
     * @param retryCount 重试次数
     * @return 处理结果
     */
    public PaymentResultDTO retryProcessNotify(String channelId, String notifyData, int retryCount) {
        logger.info("重新处理通知，渠道: {}, 重试次数: {}", channelId, retryCount);

        PaymentResultDTO lastResult = null;

        for (int i = 0; i <= retryCount; i++) {
            try {
                lastResult = processPaymentNotify(channelId, notifyData);
                if (lastResult.isSuccess()) {
                    logger.info("通知重试处理成功，渠道: {}, 第{}次尝试", channelId, i + 1);
                    return lastResult;
                }
            } catch (PaymentException e) {
                logger.warn("通知重试处理失败，渠道: {}, 第{}次尝试, 错误: {}", channelId, i + 1, e.getMessage());
                lastResult = PaymentResultDTO.failure(e.getErrorCode(), e.getMessage());

                if (i < retryCount) {
                    // 等待一段时间后重试
                    try {
                        Thread.sleep(1000 * (i + 1)); // 递增等待时间
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }

        logger.error("通知重试处理最终失败，渠道: {}, 总共尝试: {}次", channelId, retryCount + 1);
        return lastResult != null ? lastResult : PaymentResultDTO.failure("RETRY_FAILED", "All retry attempts failed");
    }

    /**
     * 获取通知处理统计信息
     *
     * @return 统计信息
     */
    public Map<String, Object> getNotifyStatistics() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("timestamp", new Date());
        stats.put("availableChannels", paymentManager.getAvailableChannelIds().length);
        stats.put("totalChannels", paymentManager.getChannelCount());

        // 添加更多统计信息...

        return stats;
    }

    /**
     * 生成成功响应
     */
    private String generateSuccessResponse(String channelId) {
        // 根据不同渠道生成不同的成功响应
        switch (channelId.toLowerCase()) {
            case "channeltest1":
                return "SUCCESS";
            case "channeltest2":
                return "{\"status\":\"success\",\"message\":\"ok\"}";
            default:
                return "OK";
        }
    }

    /**
     * 生成失败响应
     */
    private String generateFailureResponse(String channelId) {
        // 根据不同渠道生成不同的失败响应
        switch (channelId.toLowerCase()) {
            case "channeltest1":
                return "FAIL";
            case "channeltest2":
                return "{\"status\":\"error\",\"message\":\"failed\"}";
            default:
                return "ERROR";
        }
    }
}